/**
 * Copyright (c) [2021-2021] [libbylg@126.com]
 * [lplogger] is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *             http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
#ifndef LP_LOGGER_H
#define LP_LOGGER_H

#include <stdint.h>
#include <unistd.h>

#ifdef __cplusplus
#define LPEXTERN extern "C"
#else
#define LPEXTERN extern
#endif

//  最大支持多少个 sink
#define LP_SINK_COUNT_MAX 64

//  一个 sink 最多有多少个不同属性，属性编号数必须小于该值
#define LP_SINK_ATTR_COUNT_MAX 128

//  属性编号的最小值
#define LP_SINK_ATTR_MIN 0

//  字符串属性的 key 和 value 的最大长度（包括\0）
#define LP_SINK_ATTR_LEN_MAX 512

//  最多支持多少级的日志级别，日志级别的编号必须小于该值
#define LP_LEVEL_COUNT_MAX 64

//  日志级别的最小值
#define LP_LEVEL_MIN 0

//  日志级别名称的最大长度（包括\0）
#define LP_LEVEL_NAME_LEN_MAX 64

//  最多支持注册多少个格式化函数（实际不会这么多，因为每个格式化函数都对应一个 ASCII 的可见字符，而可见字符没有那么多）
#define LP_FORMAT_COUNT_MAX 128

//  一个 pattern 字符串的最大长度（含\0）
#define LP_PATTERN_LEN_MAX 512

//  目前支持的 module 个数，module 的编号应该小于该值
#define LP_MODULE_COUNT_MAX 64

//  最小的模块编号
#define LP_MODULE_MIN 0

//  模块名的最大长度（含\0）
#define LP_MODULE_NAME_LEN_MAX 64

//  缓冲区的最小容量
#define LP_BUFFER_CAP_MIN 512

//  内建属性 id 定义，这里划分了一部分属性的id作为内建属性的范围，内建属性
enum lp_sink_attr_builtin {
    LP_SINK_ATTR_PATTERN = 0,      //! 设置 sink 的输出格式的 pattern
    LP_SINK_ATTR_FLUSHLEVEL = 1,   //! 强制刷新日志的级别
    LP_SINK_ATTR_CUSTOM_BEGIN = 10 //! 用户自定义的 sink 的属性，需要大于或者等于 10
};

typedef int (*LP_ATTR_PROVIDER)(void* context, int8_t* attr_id, uintptr_t* value);

//  lp_sink_t 定义了一个 sink 的基本操作
struct lp_sink_t;
typedef void (*LP_SINK_PRINT)(struct lp_sink_t* sink, void* msg);
typedef void (*LP_SINK_FLUSH)(struct lp_sink_t* sink);
typedef int (*LP_SINK_SETUP)(struct lp_sink_t* sink, int8_t sink_attr_id, uintptr_t value);
struct lp_sink_t {
    LP_SINK_PRINT print;
    LP_SINK_FLUSH flush;
    LP_SINK_SETUP setup;
};
typedef struct lp_sink_t* (*LP_SINK_PROVIDER)(int8_t sink_id);

//  lp_format_t
struct lp_format_t;
typedef int32_t (*LP_FORMAT)(struct lp_format_t* format, void* msg, char** ptr, int32_t* len);
struct lp_format_t {
    LP_FORMAT format;
};
typedef struct lp_format_t* (*LP_FORMAT_PROVIDER)(char keychar);

struct lp_module_t {
    int8_t deflevel;
    int8_t len;
    char name[LP_MODULE_NAME_LEN_MAX];
};
typedef const struct lp_module_t* (*LP_MODULE_PROVIDER)(int8_t module_id);

struct lp_level_t {
    int8_t len;
    char name[LP_LEVEL_NAME_LEN_MAX];
};
typedef struct lp_level_t* (*LP_LEVEL_PROVIDER)(int8_t level);

struct lp_plaintext_t {
    int16_t len;
    const char* text;
};

enum lp_pattern_text_type {
    LP_PATTERN_PLAINTEXT = 0,
    LP_PATTERN_KEYCHAR = 1,
};
typedef int (*LP_PARSE_ATTRIBUTES_ENUMERATOR)(void* context, const char* key, const char* key_end, const char* val, const char* val_end);

typedef uintptr_t (*LP_MSGVIEW_PROVIDER)(void* msg, int8_t msgview_id);

typedef int (*LP_PARSE_PATTERN_ENUMERATOR)(void* context, int8_t type, const char* text, int8_t text_len);

struct lp_formatlist_t;
typedef int (*LP_FORMATLIST_ENUMERATOR)(void* context, struct lp_format_t* format);

struct lp_buffer_t {
    char* data;
    int32_t len;
    int32_t cap;
};

// clang-format off
LPEXTERN int                        lp_define_sinks(int8_t count, LP_SINK_PROVIDER provider);
LPEXTERN const struct lp_sink_t*    lp_get_sink(int8_t sink_id);
LPEXTERN int8_t                     lp_get_sinks_count();
LPEXTERN int                        lp_setup_sink(int8_t sink_id, int8_t attr_id, uintptr_t value);
LPEXTERN void                       lp_clear_sinks();

LPEXTERN int                        lp_define_formats(char escape_char, LP_FORMAT_PROVIDER provider);
LPEXTERN struct lp_format_t*        lp_get_format(char keychar);
LPEXTERN char                       lp_get_format_escape_char();
LPEXTERN void                       lp_clear_formats();
LPEXTERN void                       lp_new_format(struct lp_format_t* format);

LPEXTERN int                        lp_define_modules(int8_t count, LP_MODULE_PROVIDER provider);
LPEXTERN const struct lp_module_t*  lp_get_module(int8_t module_id);
LPEXTERN int8_t                     lp_get_modules_count();
LPEXTERN void                       lp_clear_modules();

LPEXTERN int                        lp_define_levels(int8_t count, LP_LEVEL_PROVIDER provider);
LPEXTERN struct lp_level_t*         lp_get_level(int8_t level);
LPEXTERN int8_t                     lp_get_levels_count();
LPEXTERN void                       lp_clear_levels();

LPEXTERN int                        lp_define_msgview(LP_MSGVIEW_PROVIDER provider);
LPEXTERN uintptr_t                  lp_get_msgview(void* msg, int8_t msgview_id);

LPEXTERN void                       lp_log_print(uint64_t sink_mask, int8_t module_id, int8_t level, void* msg);

LPEXTERN int                        lp_log_format(struct lp_buffer_t* buffer,struct lp_formatlist_t* formats, void* msg);

LPEXTERN int8_t                     lp_get_module_level(int8_t module_id);
LPEXTERN int                        lp_set_module_level(int8_t module_id, int8_t level);
LPEXTERN int                        lp_set_modules_level(uint64_t modules_mask, int8_t level);

LPEXTERN int                        lp_set_global_level(int8_t level);
LPEXTERN int8_t                     lp_get_global_level();

LPEXTERN int                        lp_parse_pattern(const char* pattern, void* context, LP_PARSE_PATTERN_ENUMERATOR enumerator);
LPEXTERN int                        lp_parse_attributes(const char* attributes, void* context, LP_PARSE_ATTRIBUTES_ENUMERATOR enumerator);
LPEXTERN int                        lp_compile_pattern(const char* pattern, struct lp_formatlist_t* formatlist);

LPEXTERN int32_t                    lp_format_linebreak(struct lp_format_t* format, void* msg, char** ptr, int32_t* len);
LPEXTERN int32_t                    lp_format_plaintext(struct lp_format_t* format, void* msg, char** ptr, int32_t* len);

LPEXTERN struct lp_format_t*        lp_new_format_linebreak();
LPEXTERN struct lp_format_t*        lp_new_format_plaintext(const char* plaintext, int32_t len);

LPEXTERN struct lp_formatlist_t*    lp_new_formatlist();
LPEXTERN void                       lp_del_formatlist(struct lp_formatlist_t* list);
LPEXTERN void                       lp_clear_formatlist(struct lp_formatlist_t* list, void* context, LP_FORMATLIST_ENUMERATOR clear);
LPEXTERN int                        lp_formatlist_add_tail(struct lp_formatlist_t* list, struct lp_format_t* format);
LPEXTERN int                        lp_formatlist_add_head(struct lp_formatlist_t* list, struct lp_format_t* format);
LPEXTERN void                       lp_formatlist_foreach(struct lp_formatlist_t* list, void* context, LP_FORMATLIST_ENUMERATOR enumerator);

LPEXTERN struct lp_buffer_t*        lp_new_buffer(int32_t init_cap);
LPEXTERN struct lp_buffer_t*        lp_init_buffer(struct lp_buffer_t* buffer, int32_t init_cap);
LPEXTERN void                       lp_del_buffer(struct lp_buffer_t* buffer);
LPEXTERN int                        lp_reserve_buffer(struct lp_buffer_t* buffer, int32_t new_cap);

// clang-format on

#endif // LP_LOGGER_H
